﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Exentials.Xoox.Styles;

namespace Exentials.Xoox.Spreadsheet
{
    public class XCell : XElementSequenceContainer<XElementBase>, ISequence
    {

        internal class XCellFormula : XElementBase, ISequence
        {
            public XCellFormula()
                : base("f")
            {
            }

            public string Content
            {
                get { return this.GetXElement().Value; }
                set { this.GetXElement().SetValue(value); }
            }

            #region ISequence Members

            public int Index
            {
                get { return 1; }
            }

            #endregion
        }

        internal class XCellValue : XElementBase, ISequence
        {
            public XCellValue()
                : base("v")
            {
            }

            public string Content
            {
                get { return this.GetXElement().Value; }
                set { this.GetXElement().SetValue(value); }
            }


            #region IIndex Members

            public int Index
            {
                get { return 2; }
            }

            #endregion
        }

        internal class XInlineString : XElementBase, ISequence
        {
            public XInlineString()
                : base("is")
            {
            }

            public string Content
            {
                get { return this.GetXElement().Value; }
                set { this.GetXElement().SetValue(value); }
            }

            #region IIndex Members

            public int Index
            {
                get { return 3; }
            }

            #endregion
        }

        //9 <attribute name="r" type="ST_CellRef" use="optional"/>
        //10 <attribute name="s" type="xsd:unsignedInt" use="optional" default="0"/>
        //11 <attribute name="t" type="ST_CellType" use="optional" default="n"/>
        //12 <attribute name="cm" type="xsd:unsignedInt" use="optional" default="0"/>
        //13 <attribute name="vm" type="xsd:unsignedInt" use="optional" default="0"/>
        //14 <attribute name="ph" type="xsd:boolean" use="optional" default="false"/>

        private XWorksheet _worksheet;
        private XAttributeBase<string> _reference;
        private XAttributeBase<int> _styleId;
        private XAttributeBase<string> _cellType;

        private XCellValue _value;
        private XCellFormula _formula;
        private XInlineString _inlineString;

        internal XCell()
            : base("c")
        {
            _reference = new XAttributeBase<string>(this, "r");
            _styleId = new XAttributeBase<int>(this, "s");
            _cellType = new XAttributeBase<string>(this, "t");
        }

        public void SetContent(bool value)
        {
            this.CellType = XCellType.Boolean;
            this.CellValue = value.ToString();
        }

        public void SetContent(int value)
        {
            this.CellType = XCellType.Number;
            this.CellValue = value.ToString();
        }


        public void SetContent(decimal value)
        {
            this.CellType = XCellType.Number;
            this.CellValue = value.ToString(System.Globalization.NumberFormatInfo.InvariantInfo);
        }

        public void SetContent(double value)
        {
            this.CellType = XCellType.Number;
            this.CellValue = value.ToString(System.Globalization.NumberFormatInfo.InvariantInfo);
        }

        public void SetContent(Formula value)
        {
            this.CellType = XCellType.Formula;
            CellFormula = value.ToString();
        }

        /// <summary>
        /// Set cell content with a date time value. Dates below 01/01/1900 will be stored as string
        /// </summary>
        /// <param name="value"></param>
        public void SetContent(DateTime value)
        {
            double d = value.ToOADate() - 1;
            if (d > 0)
            {
                CellType = XCellType.Number;
                CellValue = d.ToString(System.Globalization.NumberFormatInfo.InvariantInfo);
                _worksheet.Workbook.Styles.ApplyNumberFormat(this, NumberFormat.shortDate);
            }
            else
            {
                SetContent(value.ToShortDateString(), true);
            }
        }

        public void SetContent(string value)
        {
            SetContent(value, false);
        }

        public void SetContent(string value, bool shared)
        {
            this.CellType = XCellType.SharedString;
            this.CellValue = _worksheet.Workbook.SharedStrings.AddString(value, shared).ToString();
        }

        public void Clear()
        {
            if (_formula != null) _formula.Remove();
            if (_value != null) _value.Remove();
        }

        internal XWorksheet Worksheet
        {
            set
            {
                _worksheet = value;
            }
        }

        public Reference Reference
        {
            get { return _reference.Value; }
            set { _reference.Value = value.Value; }
        }

        internal string CellFormula
        {
            get
            {
                if (_formula == null) return null;
                return _formula.Content;
            }
            set
            {
                if (_formula == null)
                {
                    base.Add(_formula = new XCellFormula());
                    _formula.Content = value;
                }
            }
        }

        internal string CellValue
        {
            get
            {
                if (_value == null) return string.Empty;
                return _value.GetXElement().Value;
            }
            set
            {
                if (_value == null)
                {
                    base.Add(_value = new XCellValue());
                    _value.Content = value;
                }
            }
        }

        internal string InlineString
        {
            get
            {
                if (_inlineString == null) return string.Empty;
                return _value.Content;
            }
            set
            {
                if (_inlineString == null)
                {
                    base.Add(_inlineString = new XInlineString());
                }
                _value.Content = value;
            }
        }

        internal XCellType CellType
        {
            get
            {
                switch (_cellType.Value)
                {
                    case "b": return XCellType.Boolean;
                    case "e": return XCellType.Error;
                    case "inlineStr": return XCellType.InlineString;
                    case "n": return XCellType.Number;
                    case "s": return XCellType.SharedString;
                    case "str": return XCellType.Formula;
                    default: return XCellType.Number;
                }
            }
            set
            {
                switch (value)
                {
                    case XCellType.Boolean: _cellType.Value = "b"; break;
                    case XCellType.Error: _cellType.Value = "e"; break;
                    case XCellType.InlineString: _cellType.Value = "inlineStr"; break;
                    case XCellType.Number: _cellType.Value = "n"; break;
                    case XCellType.SharedString: _cellType.Value = "s"; break;
                    case XCellType.Formula: _cellType.Value = "str"; break;
                }
            }
        }

        public int Style
        {
            get { return _styleId.Value; }
            set { _styleId.Value = value; }
        }

        public object Value
        {
            get
            {
                switch (this.CellType)
                {
                    case XCellType.Number: return CellValue;
                    case XCellType.SharedString: return _worksheet.Workbook.SharedStrings.GetString(Convert.ToInt32(CellValue));
                    case XCellType.Formula: return CellFormula;
                    default: return 0;
                }
            }
        }

        #region IIndex Members

        public int Index
        {
            get { return Reference.Column; }
        }

        #endregion

    }
}
